﻿<?php

/*********************\
 *   haggisbot 1.0   *
 * UNDER DEVELOPMENT *
\*********************/

//REVISION $Rev: 287 $

/* "haggisbot" IRC bot
 * Copyright (C) 2008 by Mad Haggis Enterprises
 *
 *  This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

// Set up some constants
define("USER", "haggisbot");	// The bot's username on irc, replace this if you would rather have one that's different.
define("PASSWORD", "");			// The bot's password (it sends this to NickServ)
define("CHANNEL", "");			// The channel the bot goes on.  It must be an operator on this channel (in ChanServ's access list, set this bot's username's mode to +O)
define("EMAIL", "");			// The email to sign in with.
define("SERVER", "irc.freenode.net");	// The server to log into
define("PORT", 6667);	// The port to log into on the server
define("USERINFO", "The person who is using me was too lazy to set up this command.");	// Some information about you and why you have this bot working on your channel.

// Get local ip and hostname
$ch = curl_init("http://whatismyip.com/automation/n09230945.asp");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
define("LOCALIP", curl_exec($ch));
define("LOCALHOST", gethostbyaddr(LOCALIP));
curl_close($ch);

function sendcommand($commands) {
	global $socket;
	if (!$socket) {
		$socket = fsockopen(SERVER, PORT);
	}
	foreach (array_filter(explode("\n", $commands)) as $command) {
		fputs($socket, trim($command)."\n");
		sleep(0.1);
	}
}

function respond($parsedchat, $text = false) {
	if (strtolower(@$parsedchat["action"]) != "privmsg" && strtolower(@$parsedchat["action"]) != "notice") { // This function should only be used with the PRIVMSG IRC action.
		trigger_error("Wrong message type used in respond function<br>Expected \"PRIVMSG\" or \"NOTICE\", got \"".@$parsedchat["action"]."\"", E_USER_WARNING);
		return;
	}
	if ($parsedchat['ctcp'] && strtolower($parsedchat["action"]) == "privmsg") {
		//TO BE ADDED
		switch (strtolower($parsedchat['ctcp'])) {
		case "ping":
			$return = "NOTICE ".$parsedchat["nick"]." :PING ".substr($parsedchat['ctcpfull'], 5)."\n";
			break;
		case "source":
			$return = "NOTICE ".$parsedchat["nick"]." :SOURCE http://llamaslayers.googlecode.com/svn/haggisbot/\n";
			break;
		case "version":
			$return = "NOTICE ".$parsedchat["nick"]." :VERSION haggisbot v1.0a1 by Mad Haggis Enterprises\n";
			break;
		case "userinfo":
			$return = "NOTICE ".$parsedchat["nick"]." :USERINFO ".USERINFO."\n";
			break;
		case "time":
			$return = "NOTICE ".$parsedchat["nick"]." :TIME ".date("l, F jS, Y g:i:s A")."\n";
			break;
		case "clientinfo":
			switch (strtolower($parsedchat["ctcpfull"])) {
			case "clientinfo":
				$return = "NOTICE ".$parsedchat["nick"]." :CLIENTINFO CLIENTINFO USERINFO VERSION FINGER PING SOURCE TIME\n";
				break 2;
			case "clientinfo clientinfo":
				$return = "NOTICE ".$parsedchat["nick"]." :CLIENTINFO CLIENTINFO gives information on available CTCP commands\n";
				break 2;
			case "clientinfo userinfo":
				$return = "NOTICE ".$parsedchat["nick"]." :CLIENTINFO USERINFO gives information about this bot's user\n";
				break 2;
			case "clientinfo version":
				$return = "NOTICE ".$parsedchat["nick"]." :CLIENTINFO USERINFO gives information about this bot's version\n";
				break 2;
			case "clientinfo source":
				$return = "NOTICE ".$parsedchat["nick"]." :CLIENTINFO USERINFO gives information about how to obtain the source code for this bot\n";
				break 2;
			case "clientinfo time":
				$return = "NOTICE ".$parsedchat["nick"]." :CLIENTINFO USERINFO gives information about what time this bot thinks it is\n";
				break 2;
			case "clientinfo ping":
				$return = "NOTICE ".$parsedchat["nick"]." :CLIENTINFO USERINFO measures lag between this bot and your client\n";
				break 2;
			default:
				$return = "NOTICE ".$parsedchat["nick"]." :".$parsedchat["ctcpfull"]." is not a valid CTCP function for this client\n";
				break 2;
			}
		default:
			$return = "NOTICE ".$parsedchat["nick"]." :ERRMSG ".$parsedchat['ctcp']." :I do not understand that command.\n";
		}
		return $return;
	} else {
		if ($parsedchat["to"] == USER) { // Directly to the bot
			foreach (array_filter(explode("\n", $text)) as $textbit) {
				$return .= "NOTICE ".$parsedchat["nick"]." :".$textbit."\n";
			}
			return $return;
		} elseif ($parsedchat["to"] == "#".CHANNEL) { // Everyone on primary channel
			foreach (array_filter(explode("\n", $text)) as $textbit) {
				$return .= "PRIVMSG #".CHANNEL." :".$textbit."\n";
			}
			return $return;
		} elseif ($parsedchat["to"] == "##".CHANNEL) { // Everyone on secondary channel
			foreach (array_filter(explode("\n", $text)) as $textbit) {
				$return .= "PRIVMSG ##".CHANNEL." :".$textbit."\n";
			}
			return $return;
		} elseif ($parsedchat["to"] == "@#".CHANNEL) { // OPs on primary channel
			foreach (array_filter(explode("\n", $text)) as $textbit) {
				$return .= "PRIVMSG @#".CHANNEL." :".$textbit."\n";
			}
			return $return;
		} elseif ($parsedchat["to"] == "+#".CHANNEL) { // VIPs on primary channel
			foreach (array_filter(explode("\n", $text)) as $textbit) {
				$return .= "PRIVMSG +#".CHANNEL." :".$textbit."\n";
			}
			return $return;
		} elseif ($parsedchat["to"] == "@##".CHANNEL) { // OPs on secondary channel
			foreach (array_filter(explode("\n", $text)) as $textbit) {
				$return .= "PRIVMSG @##".CHANNEL." :".$textbit."\n";
			}
			return $return;
		} elseif ($parsedchat["to"] == "+##".CHANNEL) { // VIPs on secondary channel
			foreach (array_filter(explode("\n", $text)) as $textbit) {
				$return .= "PRIVMSG +##".CHANNEL." :".$textbit."\n";
			}
			return $return;
		} elseif ($parsedchat["to"] == "$*") { // Sent by an IRCop to everyone
			return;
		} elseif ($parsedchat["to"] == "AUTH") { // NOTICE AUTH during login.
			return;
		} else {
			trigger_error("Unknown message recipient \"".$parsedchat["to"]."\"", E_USER_WARNING);
			return;
		}
	}
}

function is_op($nick, $whichchat = true) {
	global $usersinchat, $usersinchat2;
	$nick = ltrim($nick, "@+");
	if ($whichchat && in_array("@".$nick, $usersinchat)) {
		return true;
	} elseif (!$whichchat && in_array("@".$nick, $usersinchat2)) {
		return true;
	}
	return false;
}

function is_vip($nick, $whichchat = true) {
	global $usersinchat, $usersinchat2;
	$nick = ltrim($nick, "@+");
	if ($whichchat && in_array("+".$nick, $usersinchat)) {
		return true;
	} elseif (!$whichchat && in_array("+".$nick, $usersinchat2)) {
		return true;
	}
	return false;
}

function is_inchat($nick, $whichchat = true) {
	global $usersinchat, $usersinchat2;
	$nick = ltrim($nick, "@+");
	if ($whichchat && (in_array("@".$nick, $usersinchat) ||  in_array("+".$nick, $usersinchat))) {
		return true;
	} elseif (!$whichchat && (in_array("@".$nick, $usersinchat2) ||  in_array("+".$nick, $usersinchat2))) {
		return true;
	}
	return false;
}

function parsechat($chatline, $isaidit = false) { // NOT READY YET
	// Add hostname if needed
	if ($isaidit) {
		$chatline = ":".USER."!n=".substr(USER, 0, 8)."@".LOCALHOST." ".$chatline;
	}
	// Initialize array
	$chatparsed = explode(" ", $chatline);
	$chatparsed["ircline"] = $chatline;
	// Remove the first colon
	$cmd = substr($ircline, 1);
	// Nickname of user who sent the command
	$chatparsed["nick"] = substr($cmd, 0, strpos($cmd, "!"));
	// The username
	$chatparsed["user"] = substr($cmd, 0, (strpos($cmd, "@") !== false) ? strpos($cmd, "@") : strpos($cmd, " "));
	// Hostname [NEEDS WORK]
	$chatparsed["host"] = substr($cmd, strpos($cmd, "@") + 1, strpos($cmd, " ") - strpos ($cmd, "@"));
	// Get rid of the first portion of the command.
	$cmd = substr($cmd, strpos($cmd, " ") + 1);
	$chatparsed["action"] = substr($cmd, 0, strpos($cmd, " "));
	$cmd = substr($cmd, strpos($cmd, " ") + 1);
	switch (strtoupper($chatparsed["action"])) {
	case "NICK":
		$chatparsed["newnick"] = substring($cmd, 1, -1);
		break;
	case "NOTICE":
	case "PRIVMSG":
		$chatparsed["to"] = trim(substr($cmd, 0, strpos($cmd, ":")));
		$cmd = substr($cmd, strpos($cmd, ":") + 1);
		if (strpos($cmd, "") === 0) {
			$chatparsed["ctcp"] = substr($cmd, 1, ((strpos($cmd, " ")) ? strpos($cmd, " ") : strpos($cmd, "")) - 1);
			$chatparsed["ctcpfull"] = substr(trim($cmd), 1, -1);
		}
		$chatparsed["command"] = substr($cmd, 0, ((strpos($cmd, " ")) ? strpos($cmd, " ") : strlen($cmd)));
		$chatparsed["commandargscount"] = substr_count($cmd, " ");
		$argarray = explode(" ", $cmd);
		unset($argarray[0]);
		for ($i = 0; $i < $chatparsed["commandargscount"];) {
			$chatparsed["commandarg".$i] = $argarray[++$i];
			$chatparsed["commandarg".($i-1)."on"] = implode(" ", $argarray);
			unset($argarray[$i]);
		}
		break;
	}
	return $chatparsed;
}

set_time_limit(0);
sendcommand("USER ".USER." \"".EMAIL."\" ".USER." :\"haggisbot\" IRC bot\nNICK ".USER."\nPRIVMSG NickServ :ID ".USER." ".PASSWORD);
sleep(1);
sendcommand("JOIN #".CHANNEL."\nJOIN ##".CHANNEL);
global $socket;
while(1) {
	while($data = fgets($socket, 128)) {
		while (!strpos($data, "\n")) {
			$data .= fgets($socket, 128);
		}
		if (substr($data, 0, 5) == "PING :") {
			sendcommand(trim(str_replace($data, "PING", "PONG")));
		}
		$parsedchat = parsechat($chatline);
		if ($parsedchat["ctcp"]) {
			sendcommand(respond($parsedchat));
		}
		if (strtoupper($parsedchat["action"]) == "JOIN" || strtoupper($parsedchat["action"]) == "PART" || strtoupper($parsedchat["action"]) == "QUIT" || strtoupper($parsedchat["action"]) == "NICK" || strtoupper($parsedchat["action"]) == "KICK" || strtoupper($parsedchat["action"]) == "MODE") {
			sendcommand($socket, "NAMES #".CHANNEL."\nNAMES ##".CHANNEL);
		}
		if ($parsedchat["action"] == "353") {
			global $usersinchat, $usersinchat2;
			$usersinchatarray = explode(" ", trim($data));
			unset($usersinchatarray[0]);
			unset($usersinchatarray[1]);
			unset($usersinchatarray[2]);
			unset($usersinchatarray[3]);
			$whichchat = !(substr($usersinchatarray[4], 1, 1) == "#");
			unset($usersinchatarray[4]);
			$usersinchatarray[5] = substr($usersinchatarray[5], 1);
			$usersinchatarray = array_filter($usersinchatarray);
			if ($whichchat) {
				$usersinchat = $usersinchatarray;
			} else {
				$usersinchat2 = $usersinchatarray;
			}
		}
		if ($parsedchat["command"] && $parsedchat["command"] == "!leave") {
			if ($parsedchat["commandargscount"] == 0 && strpos($parsedchat["to"], "#") !== false && is_op($parsedchat["nick"], !strpos($parsedchat["to"], "#"))) {
				sendcommand("PART ".ltrim($parsedchat["to"], "+@")." :Leaving on ".$parsedchat["nick"]."'s request.");
			} elseif ($parsedchat["commandargscount"] == 1 && is_op($parsedchat["nick"], !strpos($parsedchat["commandarg1"], "#"))) {
				sendcommand("PART ".$parsedchat["commandarg1"]." :Leaving on ".$parsedchat["nick"]."'s request.");
			} else {
				sendcommand(respond($parsedchat, "I think you're using my !leave command wrong."));
			}
		}
		flush();
	}
}

?>